C++

vector 和 string

"好好学习标准库"

Posted by JosonChan on 2020-11-01

string

  • string.size()函数返回的是一个无符号的数,因此在表达式中混用带符号数以及无符号数都可能产生意向不到的结果。假设 n 是一个具有负值的 int,则表达式 s.size() < n 则会把 n 转换成一个很大的无符号数,带来异常,最好使用 std::size_t

  • 如果一次想读入一个词,使用 cin,如果想要一次读入一行,使用 getline

        string a;
        while (getline(cin,a)){
            cout << a << endl;
        }
        while(cin >> a){
            cout << a << endl;
        }
    
  • C++ 标准库中除了定义C语言特有的功能外,也兼容了C语言的标准库。C语言的头文件命名为 name.h,C则命名为cname,这里的 c表示这是一个属于C语言标准库的头文件。在C++ 中尽量使用C++版本的C语言标准库。

  • C++11 定义了一种新的遍历语句:range for:

    string str("something");
    for (size_t c : str){
        cout << c << endl;// 注意这里改变 c 不会改变 str,因为只是一个临时变量
    }
    
    
    for (auto &c : str){// 如果想要改变则需要用引用
        c = toupper(c);
    }
    

Vector

  • C++ 11取消了vector对象是vector 时的定义标准,过去在外层对象的右尖括号和其元素之间需要有一个空格,C++11不需要。

    #include <vector>
    using namespace std;
    vector<vector<int>> matrix;// C++11
    vector<vector<int> > matrix;// 早期标准
    
  • 如果循环体内部包含有向 vector 对象添加元素的语句,则不能使range for 语句,因为range for 语句要求遍历对象拥有能返回迭代器的 begin 和 end 成员。如果我们在 range for 语句中添加或者删除了元素,则 end() 函数的值就可能变得无效了。

迭代器

  • 迭代器的标准类型使用 iterator 以及 const_itrator 来表示迭代器的类型:

    vector<int> arr1;
    const vector<int> arr2;
    
    vector<int>::iterator it;
    vector<int>::const_iterator it;// 和常量指针差不多,只能读取值,不能改变值
    
  • begin()以及end() 根据对象是否是常量来返回迭代器,如果想一直得到 const_iterator 类型的返回值,C++11新标准引入了两个函数,分别是cbegin()以及 cend()

  • 某些对容器的操作会导致迭代器失效,一种是不能在 range for 语句循环中向 vector 对象添加元素,另外一个限制是任何一种可能改变 vector 对象容量的操作,比如 push_back ,都会使得 vector 对象的迭代器失效。

复杂的数组声明

  • 对于数组来说,由内向外阅读比从右到左好。由于数组是一个对象,因此有数组的指针以及数组的引用,但是没有数组元素没有引用类型。

    int *ptrs[10];// ptr 是一个存放10个指针的数组
    int (*ptr)[10]=arr;// ptr 是一个存放10个int的数组的指针
    int (&ptr)[10]=&arr;// ptr是一个存放10个int的数组的引用
    int *(&ptr)[10]=&ptrs;// ptr 是一个存放10个int*的数组的引用
    
  • 数组的维度必须是一个常量表达式,可以使用 constexpr。

    unsigned int i = 10;
    int a[i];// 错误
    

    但是我在我的机器上使用了如下:

    int fun1(int x){
        return x;
    }
    
    int main(){
        unsigned buf_size = 1024;
        int x = 100;
        int nums[fun1(x)] = {0};
    
        cout << nums[0] << endl;
    }
    

    并没有发生错误,原因是因为我使用的 g++ 进行编译,可变长数组是g++编译器的扩展,C++ 是不允许使用这种用法。

    参考:数组维度定义

  • C++11 为了获取数组的尾后指针,引入了两个函数, begin()end(),需要包括 iterator头文件。

    #include <iterator>
    int nums[10] = {0};
    for(int* ptr = begin(nums);ptr != end(nums);++ptr){
        (*ptr)++;
    }
    
    for(auto i : nums){
        cout << i << endl;
    }
    
  • 内置的下标运算符所用的索引值不是无符号类型,而标准库规定使用的是无符号的类型。

多维数组

  • 要使用 range for 语句处理多维数组,除了最外层的循环之外,其他所有循环的控制变量都应该是引用类型。

    int ia[10][10];
    for (auto &row : ia){// 如果不是引用,则auto 会把row 当成int* 指针
    	for (auto col : row){
    		col = 1;
    	}
    }
    
  • 因为多维数组实际上是数组的数组,所以由多维数组名转换得到的指针实际上是指向第一个内层数组的指针,需要注意的是,解引用之后是指向该行第一个元素的指针。

        constexpr size_t rowCnt = 3, colCnt = 4;
        int ia[rowCnt][colCnt] = {0};
    
        // 传统的for循环
        for(size_t i=0;i!=rowCnt;++i){
            for(size_t j=0;j!=colCnt;++j){
                cout &lt;&lt; ia[i][j] &lt;&lt; endl;
            }
        }
        cout &lt;&lt; &quot; ----------------------&quot; &lt;&lt; endl;
        // 使用 for range
        for (int (&amp;row)[colCnt] : ia){
            for (int col : row){
                cout &lt;&lt; col &lt;&lt; endl;
            }
        }
        cout &lt;&lt; &quot; ----------------------&quot; &lt;&lt; endl;
        // 使用指针
        for(int (*rowptr)[colCnt] = ia;rowptr != ia+3;rowptr++){
            for(int* colptr = *rowptr;colptr != *rowptr+4;colptr++){
                cout  &lt;&lt; *colptr &lt;&lt; endl;
            }
        }
    	// 使用begin 和 end
    	for(auto row = begin(ia);row != end(ia); ++row){
            for(auto col=begin(*row);col != end(*row);++col){
                cout &lt;&lt; *col &lt;&lt; endl;
            }
        }
    --
    
  • 同时我们可以用别名来代替:

        constexpr size_t rowCnt = 3, colCnt = 4;
        int ia[rowCnt][colCnt] = {0};
    
        using int_array_4 = int[4];
    
        // 传统的for循环
        for(auto i=0;i!=rowCnt;++i){
            for(auto j=0;j!=colCnt;++j){
                cout << ia[i][j] << endl;
            }
        }
        cout << " ----------------------" << endl;
        // 使用 for range
        for (int_array_4 &row : ia){
            for (int col : row){
                cout << col << endl;
            }
        }
        cout << " ----------------------" << endl;
        // 使用指针
        for(int_array_4 *rowptr = begin(ia);rowptr != end(ia);rowptr++){
            for(int *colptr = *rowptr;colptr != *rowptr+4;colptr++){
                cout  << *colptr << endl;
            }
        }